#include "AIEntityController.h"
#include "Pathing.h"

#define PATH_RECURSION_DEPTH 6

const HashedString AIEntityController::type("AIEntityController");

AIEntityController::AIEntityController( Entity* entity ) : IEntityController(entity)
{
	m_orientation = (OrientationComponent*)(m_entity->FindComponent(OrientationComponent::type));
	m_rigidbody = (RigidBodyComponent*)(m_entity->FindComponent(RigidBodyComponent::type));
	m_status = (StatusComponent*)(m_entity->FindComponent(StatusComponent::type));
	m_combat = (CombatComponent*)(m_entity->FindComponent(CombatComponent::type));
	LinkPosition(m_orientation->getPosition());
}

Pathing::Vehicle& AIEntityController::Vehicle()
{
	return m_vehicle;
}

void AIEntityController::LinkPosition( Subject<Maths::Vector3D>& position )
{
	m_position = new DoubleValueTrigger<Maths::Vector3D>(&position, &m_vehicle.getPosition());
}

void AIEntityController::UpdateVelocity( Maths::Vector3D& velocity )
{
	if (m_rigidbody)
	{
		m_rigidbody->getBody()->getRigidBody()->setLinearVelocity(btVector3(velocity.X(), velocity.Y(), velocity.Z()));
	}
}

void AIEntityController::UpdateStatus( HashedString status, int value )
{
	if (m_status)
	{
		StatusComponent::Status& stat = m_status->getStatus(status);
		stat = value;
	}
}

void AIEntityController::getPosition( Maths::Vector3D& position )
{
	position = m_orientation->getPosition().getObject();
}

void AIEntityController::getStatus( HashedString status, int& value )
{
	if (m_status)
	{
		StatusComponent::Status& stat = m_status->getStatus(status);
		value = stat.getObject();
	}
}

void AIEntityController::getDirection( Maths::Vector3D& direction )
{
	m_vehicle.Direction(direction);
}

void AIEntityController::Update()
{
	m_behavior->Update();
}

void AIEntityController::UpdatePath()
{
	float costOfPath;
	if (m_world.isValid())
	{
		m_vehicle.Path().clear();
		Pathing::GetPathofVehicleToDestination(m_vehicle, m_world->Obstacles(), costOfPath, m_vehicle.Path(), PATH_RECURSION_DEPTH);
	}
}

void AIEntityController::UpdateDirectionNode()
{
	if (m_world.isValid())
		if (LOSVehicleNextNode( m_vehicle, m_world->Obstacles() ))				// Can AI see the next node?
			m_vehicle.PopPathingPoint();							// Move towards it if so
}

void AIEntityController::UpdateDestination( Maths::Vector3D& destination )
{
	m_vehicle.Destination(destination);
}

void AIEntityController::setWorld( Pointer<Pathing::World>& world )
{
	m_world = world;
}

const HashedString& AIEntityController::Type()
{
	return type;
}

std::list<Maths::Vector3D>& AIEntityController::getWaypoints()
{
	return m_waypoints;
}

void AIEntityController::Behavior( Pointer<IBehavior> behavior )
{
	m_behavior = behavior;
}

Pointer<IBehavior> AIEntityController::Behavior( )
{
	return m_behavior;
}

void AIEntityController::ToXML( tinyxml2::XMLPrinter& printer )
{
	printer.OpenElement("Behavior");
	printer.PushAttribute("Type", m_behavior->Type().getString().c_str());

	m_behavior->ToXML(printer);

	printer.CloseElement();	

	for (std::list<Maths::Vector3D>::iterator it = m_waypoints.begin(); it != m_waypoints.end(); ++it)
	{
		printer.OpenElement("Waypoint");
		
		char buffer[50];
		sprintf_s(buffer, 50, "%.3f %.3f %.3f", it->X(), it->Y(), it->Z());

		printer.PushAttribute("Vector", buffer);

		printer.CloseElement();
	}
}


Combat::IAbility::Vector_t& AIEntityController::getAbilities()
{
	return m_combat->Combatant()->Abilities();
}